/*
 * RW_lock.c
 *
 *  Created on: Dec 18, 2014
 *      Author: Uzi
 */

#include "RW_lock.h"
#include <stdio.h>
int rwlock_init(RWLock* lock) {
	pthread_mutexattr_t attr;
	int retval;

	lock->readers = 0;
	lock->writers = 0;
	//init attribute
	retval = pthread_mutexattr_init(&attr);
	if (retval) {
		return retval;
	}
	//set attribute to error checking mutex
	retval = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
	if (retval) {
		return retval;
	}
	//init main lock with the right attribute
	retval = pthread_mutex_init(&(lock->mutex), &attr);
	if (retval) {
		return retval;
	}
	//init condition #1
	retval = pthread_cond_init(&(lock->readers_waiting), NULL);
	if (retval) {
		return retval;
	}
	//init condition #2
	retval = pthread_cond_init(&(lock->writers_waiting), NULL);
	if (retval) {
		return retval;
	}
	return retval;
}

void wrlock(RWLock* lock) {
	//printf("\nwrite Lock #%d",(int)lock);
	pthread_mutex_lock(&(lock->mutex));
	while (((lock->writers > 0) || (lock->readers > 0))) {
		pthread_cond_wait(&(lock->writers_waiting), &(lock->mutex));
	}
	lock->writers++;
	pthread_mutex_unlock(&(lock->mutex));
	//printf("\ndone write lock #%d",(int)lock);
}

void rlock(RWLock* lock) {

	pthread_mutex_lock(&(lock->mutex));
	while (lock->writers > 0) {
		pthread_cond_wait(&(lock->readers_waiting), &(lock->mutex));
	}
	lock->readers++;
	pthread_mutex_unlock(&(lock->mutex));

}

void wrunlock(RWLock* lock) {
	//printf("\nwrite UnLock #%d",(int)lock);

	pthread_mutex_lock(&(lock->mutex));
	lock->writers--;
	if ((lock->writers) == 0) {
		pthread_cond_broadcast(&(lock->readers_waiting));
		pthread_cond_signal(&(lock->writers_waiting));
	}
	pthread_mutex_unlock(&(lock->mutex));
	//printf("\n done write unlock #%d",(int)lock);

}

void runlock(RWLock* lock) {
	pthread_mutex_lock(&(lock->mutex));
	lock->readers--;
	if ((lock->readers) == 0) {
		pthread_cond_signal(&(lock->writers_waiting));
	}
	pthread_mutex_unlock(&(lock->mutex));

}

void rwlock_destroy(RWLock* lock) {
	pthread_cond_destroy(&(lock->readers_waiting));
	pthread_cond_destroy(&(lock->writers_waiting));
	pthread_mutex_destroy(&(lock->mutex));
}

